package uage.compiler

import uage.ast._
import scala.collection.mutable.ListBuffer
import scala.util.control.Breaks
import uage.exception._
import uage.logger._

class Parser(val tokenizer:Tokenizer) {
  var curToken = (0,"")
  
  val main = GraphExpr()  //create main node
  
  def start(){
    //tokenizer.nextChar() //begin
    while(tokenizer.hasNext()){
      curToken = tokenizer.nextToken()
  	  println(curToken)
  	  
    }
    println(tokenizer.nextToken())
  }
  
  def parse() = {
    if(tokenizer.curToken._1 == 0){
      tokenizer.nextToken()
    }
    var times = 0 //Cycle times
    while(tokenizer.curToken._1 != -1 && times < 200){
      times = times + 1 
      parseDomain(main)
    }
    logger.test(main)
    logger.test(main.eval())
  }
  
  /**
   * 生成表达式
   * e.g. a + b || c = a + b || f(x) || a{...} || a(...){...} || a = (...){...}
   * || f(x) = x + 1 || f(x) = {...}
   */
  def genExpr():Expr = {
    var expr = genAtomExpr()
    expr match {
      case symbol:SymbolExpr => {
        if(tokenizer.curToken._1 == ':' ) { //e.g. a : ... a{...}
          tokenizer.nextToken() //eat ':'
          var exprRight = genAtomExpr() //e.g. a:b || a:"str" || a:520 || a:(...) || a:{...} || a:(...){...} ||...
          return PairExpr(expr,exprRight)
        } else if(tokenizer.curToken._1 == '='){ //e.g. a= b...
          tokenizer.nextToken() //eat '='
          return AssignExpr(symbol,genExpr())
        }else if(Identifier.isOperator(SymbolExpr(tokenizer.curToken._2))){ //e.g. a + b 
          var operator = genOperatorExpr(expr, SymbolExpr(tokenizer.curToken._2))
          return operator
        } else if(tokenizer.curToken._1 == '{'){ //e.g. aym{...}
          var graph = parseBrace()
          return PairExpr(expr,graph)
        } else if(tokenizer.curToken._1 == ';' || tokenizer.curToken._1 == ','){ //e.g. sym, || sym;
          return symbol
        }
//        else if(tokenizer.curToken._1 == '.'){ //e.g. a.b
//          var chain = ChainExpr()
//    		  chain.list.append(symbol)
//          tokenizer.nextToken() //eat '.'
//          var expr = genAtomExpr()
//          chain.list.append(expr)
//          while(tokenizer.curToken._1 == '.'){
//            tokenizer.nextToken() //eat '.'
//            expr = genAtomExpr()
//            chain.list.append(expr)
//          }
//          return InvokeExpr(chain,null)
//        }
        return symbol
      }
      case invoke:InvokeExpr => { //e.g. a() ...
        if(tokenizer.curToken._1 == '{'){ //e.g. a(...){...}...
          var graph = parseBrace()
          graph.params = invoke.params
          return PairExpr(invoke.symbol,graph)
        } else if(tokenizer.curToken._1 == '='){ //e.g. a() = ... means define a function
          tokenizer.nextToken() //eat '='
          if(tokenizer.curToken._1 == '{' || tokenizer.curToken._1 == Identifier.BEGIN_BRACE){ //e.g. a(..) = {..}
            var graph = parseBrace()
            graph.params = invoke.params
            return AssignExpr(invoke.symbol,graph)
            //return OperatorExpr(SymbolExpr("="),invoke.symbol,graph)
          } else { //e.g. f(x) = a + b
            var graph = GraphExpr()
            graph.params = invoke.params
            var expr = genExpr()
            graph.exprStream.append(expr)
            return AssignExpr(invoke.symbol,graph)
            //return OperatorExpr(SymbolExpr("="),invoke.symbol,graph)
          }
        }else if(Identifier.isOperator(SymbolExpr(tokenizer.curToken._2))){ //e.g. a()+ ... || a() - ...
          return genOperatorExpr(invoke, SymbolExpr(tokenizer.curToken._2))
        } else if(tokenizer.curToken._1 == ':'){ //e.g. a():...
          tokenizer.nextToken() //eat ':'
          if(tokenizer.curToken._1 != '{' || tokenizer.curToken._1 == Identifier.BEGIN_BRACE) throw SyntaxUnrealizedException(tokenizer.curToken) 
          var graph = parseBrace() //e.g. a():{...}
          graph.params = invoke.params
          return graph
        } else if(tokenizer.curToken._1 == ';' || tokenizer.curToken._1 == ','){ //e.g. f(...), || f(...);
          return invoke
        }
        return invoke
      }
      case dotExpr:DotExpr => { //e.g. a.b...
        if(tokenizer.curToken._1 == '='){
          tokenizer.nextToken() //eat '='
          var right = genExpr()
          return AssignExpr(dotExpr,right)
        }else if(Identifier.isOperator(SymbolExpr(tokenizer.curToken._2))){
          var operator = genOperatorExpr(dotExpr, SymbolExpr(tokenizer.curToken._2))
          return operator
        }
        return dotExpr
        
      }
      case op:OperatorExpr => { //e.g. !expr || +expr || -expr
        if(Identifier.isOperator(SymbolExpr(tokenizer.curToken._2))){
          var operator = genOperatorExpr(op, SymbolExpr(tokenizer.curToken._2))
          return operator
        }
        return op
      }
      case tuple:TupleExpr => {
        if(Identifier.isOperator(SymbolExpr(tokenizer.curToken._2))){ //e.g. (2 + 5) + ...
          return genOperatorExpr(tuple, SymbolExpr(tokenizer.curToken._2))
        }
        return tuple
      }
      case list:ListExpr => {
        return list
      }
      case graph:GraphExpr => {
        return graph
      }
      case number:NumberExpr => {
        if(Identifier.isOperator(SymbolExpr(tokenizer.curToken._2))) { //e.g. 1 + 2 || ...
          genOperatorExpr(number, SymbolExpr(tokenizer.curToken._2))
        } else if(tokenizer.curToken._1 == ':'){ //e.g. 1:"22"
          tokenizer.nextToken() //eat ':'
          var rightExpr = genAtomExpr()
          PairExpr(number,rightExpr)
        } else{
          number
        }
      }
      case string:StringExpr => {
        if(tokenizer.curToken._1 == ':'){ //e.g. "myz":025
          tokenizer.nextToken() //eat ':'
          var rightExpr = genAtomExpr()
          PairExpr(string,rightExpr)
        } else {
        	string
        }
      }
//      case constant if(constant.isInstanceOf[NumberExpr] || constant.isInstanceOf[StringExpr]) => {
//        return constant
//      }
      case other => {
        throw SyntaxException(other)
      }
    }
  }
  
  /**
   * 生成语元
   * e.g. a || a() || (...) || {...} || [...] || (...){...} || i++ || i-- || !i || ...
   */
  def genAtomExpr():Expr = {
    tokenizer.curToken._1 match {
      case Identifier.SYMBOL => {
        var symbol = SymbolExpr(tokenizer.curToken._2)
        tokenizer.nextToken() //eat 
        tokenizer.curToken._1 match {
          //e.g. a+... a-... a* ... just return a
//          case c if(c == Identifier.SYMBOL || c == Identifier.STRING || c == Identifier.NUMBER || c == ',' || c == ';'
//              || c == ':' || c == '{' || c == '[' || c == -1 || c == ')' || c == '}' || c == ']'
//              || Identifier.isOperator(SymbolExpr(tokenizer.curToken._2))
//              || c == Identifier.BEGIN_BRACE
//              || c == Identifier.BEGIN_PAREN) => { 
//            return symbol
//          }
          case c if(c != '(' && c != '.' && c != Identifier.PLUSPLUS && c != Identifier.SUBSUB) => { //a
            return symbol
          }
          case '(' => { //e.g. a()...
            var tuple = parseParen()
            //e.g. a() = ... a() + ... 
//            if(tokenizer.curToken._1 == ':' || tokenizer.curToken._1 == '{' || tokenizer.curToken._1 == -1
//                || tokenizer.curToken._1 == ',' || tokenizer.curToken._1 == ';'
//                || tokenizer.curToken._1 == '[' || tokenizer.curToken._1 == ']'
//                || tokenizer.curToken._1 == '}' || tokenizer.curToken._1 == ')' || tokenizer.curToken._1 == '('
//                || tokenizer.curToken._1 == Identifier.STRING || tokenizer.curToken._1 == Identifier.SYMBOL || tokenizer.curToken._1 == Identifier.NUMBER
//                || Identifier.isOperator(SymbolExpr(tokenizer.curToken._2))
//                || tokenizer.curToken._1 == Identifier.BEGIN_BRACE
//                || tokenizer.curToken._1 == Identifier.BEGIN_PAREN){
//              return InvokeExpr(symbol,tuple)
//            } 
            if(tokenizer.curToken._1 == '.'){ //e.g. symbol().other...
              return genDotExpr(symbol)
            } else if(tokenizer.curToken._1 != '{'){ //e.g. symbol() 
              return InvokeExpr(symbol,tuple)
            } else { //e.g. symbol(){...}
              return InvokeExpr(symbol,tuple)
            }
          }
          case '.' => { //e.g. symbol.other
            var dotExpr = genDotExpr(symbol)
            return dotExpr
          }
          case Identifier.PLUSPLUS => { //e.g. symbol++
            tokenizer.nextToken() //eat "++"
            var operator = OperatorExpr(SymbolExpr("++"),symbol,nil)
            return operator
          }
          case Identifier.SUBSUB => { //e.g. symbol--
            tokenizer.nextToken() //eat "--"
            var operator = OperatorExpr(SymbolExpr("--"),symbol,nil)
            return operator
          }
          case other => {
            throw SyntaxException(tokenizer.curToken)
          }
        }
      }
      case Identifier.STRING => { //e.g. "hello"
        var str = StringExpr(tokenizer.curToken._2)
        tokenizer.nextToken() //finish and jump to the next step
        if(tokenizer.curToken._1 == '.'){ //e.g. "str".length
          return genDotExpr(str)
        } else {
          str
        }
      }
      case Identifier.NUMBER => { //e.g. 2 + 3 || 2 + f(x)
         var num = NumberExpr(tokenizer.curToken._2.toDouble)
         tokenizer.nextToken() //finish and jump to the next step
      	 if(tokenizer.curToken._1 == '.'){ //e.g. 555.some...
      	   return genDotExpr(num)
      	 } else {
      	   return num
      	 }
      }
      case '!' => { //e.g. !expr
        tokenizer.nextToken() //eat '!'
        var expr = genAtomExpr()
        return OperatorExpr(SymbolExpr("!"),expr,nil)
      }
      case c if(c =='{' || c == Identifier.BEGIN_BRACE) => {
        var graph = parseBrace()
        return graph
      }
      //e.g. (a,b,...) = expr ||  ({...},b,...) = expr || ((...),b,...) = expr
      case c if(c == '(' || c == Identifier.BEGIN_PAREN) => {
        var list = parseParen()
        if(tokenizer.curToken._1 == '{'){ //e.g. (...){...}
          var graph = parseBrace()
          graph.params = list
          return graph
        } else if(tokenizer.curToken._1 == '='){ //e.g. (a) = other => a = other
          if(list.length == 1){
            return list(0)
          }
        }
        return TupleExpr(list)
      }
      //e.g. [a,b,...] = expr || ...
      case '[' => {
        var list = parseBracket()
        return ListExpr(list)
      }
      case ',' => {
        tokenizer.nextToken() //eat
        return genAtomExpr()
      }
      case ';' => {
        tokenizer.nextToken() //eat
        return genAtomExpr()
      }
      case -1 => {
        nil
      }
      case e => {
        throw SyntaxException(tokenizer.curToken)
      }
    }
  }
  
  /**
   * .运算符作为一个整体解析
   */
  def genDotExpr(pre:Expr):DotExpr = {
    tokenizer.nextToken() //eat '.'
    var next:Expr = nil
    tokenizer.curToken._1 match {
      case Identifier.SYMBOL => { //e.g. pre.sym
        next = SymbolExpr(tokenizer.curToken._2)
        tokenizer.nextToken() //eat symbol
        if(tokenizer.curToken._1 == '('){ //e.g. pre.next()
          var tuple = parseParen()
          var invokeExpr = InvokeExpr(next,tuple)
          if(tokenizer.curToken._1 == '.'){ //e.g. pre.next().other
            var dot = DotExpr(pre,invokeExpr)
            return genDotExpr(dot)
          } else { //e.g. pre.next() 
            return DotExpr(pre,invokeExpr)
          }
        } else if(tokenizer.curToken._1 == '.') { //e.g. pre.next.
          var dot = DotExpr(pre,next)
          return genDotExpr(dot)
        } else { //e.g. pre.next
          return DotExpr(pre,next)
        }
      }
      case Identifier.STRING => { //e.g. pre."str"
        var next = StringExpr(tokenizer.curToken._2)
        tokenizer.nextToken() //eat next
        var dot = DotExpr(pre,next)
        if(tokenizer.curToken._1 == '.'){ //e.g. pre."str".other....
          return genDotExpr(dot)
        } else { //e.g. pre."str"
          return dot
        }
      }
      case Identifier.NUMBER => {
        var next = NumberExpr(tokenizer.curToken._2.toDouble)
    		tokenizer.nextToken() //eat next
        var dot = DotExpr(pre,next)
        if(tokenizer.curToken._1 == '.'){ //e.g. pre.1.other
          return genDotExpr(dot)
        }else { //e.g. pre.1
          return dot
        }
      }
      case c if(c == '('|| c == Identifier.BEGIN_PAREN) => { //e.g. a.(var) or a.    (var)
        var next = TupleExpr(parseParen())
        if(next.elems.size != 1) throw ParamLengthMismatchException(next)
        var dot = DotExpr(pre,next)
        if(tokenizer.curToken._1 == '.'){ //e.g. a.(var).other
          return genDotExpr(dot)
        } else {
        	return dot
        }
      }
      case other => {
        throw SyntaxUnrealizedException(tokenizer.curToken)
      }
    }
  }
  
  /**
   * e.g. a + b || 3 + 4 || 3 + b || a + 3 * 5 || a + (3 + 5) || ...
   */
  def genOperatorExpr(left:Expr,op:SymbolExpr):OperatorExpr = {
    tokenizer.nextToken() //eat op
    var right = genAtomExpr() //get right
    var nextOp = SymbolExpr(tokenizer.curToken._2)
    if(Identifier.isOperator(nextOp)){ 
      if(Identifier.weight.get(op) >= Identifier.weight.get(nextOp)){ //e.g. 1 + 2 + 3
        return genOperatorExpr(OperatorExpr(op,left,right),nextOp)
      } else { //e.g. 1 + 2 * 3
        return OperatorExpr(op,left, genOperatorExpr(right, nextOp))
      }
    } else {
    	return OperatorExpr(op,left,right)
    }
    
  }
  
  def genGraphExpr():GraphExpr = {
    var graph = GraphExpr()
    while(tokenizer.curToken._1 != '}'){
      parseDomain(graph)
    }
    return graph
  }
  
  /**
   * 解析作用域body
   */
  def parseDomain(graph:GraphExpr) = {
    var expr = genExpr()
    expr match {
      case PairExpr(symbol,expr) => { //generate node
        if(expr.isInstanceOf[GraphExpr]){
          expr.asInstanceOf[GraphExpr].parent = graph //parent node
        }
        graph.nodes.put(symbol, expr)
      }
      case OperatorExpr(op,left,right) => { //e.g. c = a + b || a + b || ...
        graph.exprStream.append(OperatorExpr(op,left,right))
      }
      case InvokeExpr(symbol,params) => { //
        params.foreach(param => {
          if(param.isInstanceOf[GraphExpr]) param.asInstanceOf[GraphExpr].parent = graph
        })
        graph.exprStream.append(InvokeExpr(symbol,params))
      }
      case assign:AssignExpr => {
        if(assign.right.isInstanceOf[GraphExpr]){
          assign.right.asInstanceOf[GraphExpr].parent = graph //parent node
        }
        graph.exprStream.append(assign)
      }
      case SymbolExpr(_) => {
        graph.exprStream.append(expr)
      }
      case StringExpr(_) => {
        graph.exprStream.append(expr)
      }
      case NumberExpr(_) => {
        graph.exprStream.append(expr)
      }
      case DotExpr(_,_) => {
        graph.exprStream.append(expr)
      }
      case TupleExpr(elems) => { //e.g. (...)
        elems.foreach(elem => {
          if(elem.isInstanceOf[GraphExpr]) elem.asInstanceOf[GraphExpr].parent = graph
        })
        graph.exprStream.append(expr)
      }
      case ListExpr(_) => { //e.g. [...]
        graph.exprStream.append(expr)
      }
      case GraphExpr() => {
        expr.asInstanceOf[GraphExpr].parent = graph //parent node
        graph.exprStream.append(expr)
      }
      case IfExpr(_) => {
        graph.exprStream.append(expr)
      }
      case other => {
        throw UnknownExprException(expr)
      }
    }
  }
  
  def genTuple():ListBuffer[Expr] = {
    var list = ListBuffer[Expr]()
    while(tokenizer.curToken._1 != ')'){
      var expr = genExpr()
      if(tokenizer.curToken._1 == ','){ //e.g. (expr,...)
    	  tokenizer.nextToken() //eat ','
    	  list.append(expr)
      } else if(tokenizer.curToken._1 == ')'){ //e.g. (expr,expr2)
        list.append(expr)
      }else if(tokenizer.curToken._1 != ')'){ //e.g. (11 13,66,...) => (13,16...)
//        var graph = GraphExpr()
//        graph.exprStream.append(expr)
//        while(tokenizer.curToken._1 != ',' && tokenizer.curToken._1 != ')'){ //e.g. (a b c() d,...)
//        	parseDomain(graph)
//        } 
//        if(tokenizer.curToken._1 == ',') tokenizer.nextToken() //eat
//        list.append(graph)
        var listBuffer = ListBuffer[Expr]()
        while(tokenizer.curToken._1 != ',' && tokenizer.curToken._1 != ')'){ //e.g. (sym a b c d,...)
          listBuffer.append(genExpr())
        }
        var invokeExpr = InvokeExpr(expr,listBuffer)
        if(tokenizer.curToken._1 == ',') tokenizer.nextToken() //eat
        list.append(invokeExpr)
      }
    }
    return list
  }
  
  def genList():ListBuffer[Expr] = {
    var list = ListBuffer[Expr]()
    while(tokenizer.curToken._1 != ']'){
      var expr = genExpr()
      if(tokenizer.curToken._1 == ','){ //e.g. (expr,...)
    	  tokenizer.nextToken() //eat ','
    	  list.append(expr)
      } else if(tokenizer.curToken._1 == ']'){ //e.g. (expr,expr2)
        list.append(expr)
      }
    }
    return list
  }
  
  //e.g. {expr*}
  def parseBrace():GraphExpr = {
    tokenizer.nextToken() //eat '{'
    var expr = genGraphExpr()
    tokenizer.nextToken() //eat '}'
    return expr
  }
  //e.g. (a,b,c,...)
  def parseParen():ListBuffer[Expr] = {
    tokenizer.nextToken() //eat '('
    var rst = genTuple()
    tokenizer.nextToken() //eat ')'
    return rst
  }
  
  //e.g. [a,b,c,...]
  def parseBracket():ListBuffer[Expr] = {
    tokenizer.nextToken() //eat '['
    var rst = genList()
    tokenizer.nextToken() //eat ']'
    return rst
  }
}